﻿#include "command.h"
#include "ais/ais_curve.h"
#include "ais/ais_mesh.h"
#include "ais/ais_point.h"
#include "ais/ais_surface.h"
#include "ais/ais_vector.h"
#include "topo/topo_all.h"

CAGD::Command::Command() : m_context(AIS_Context::ShareContext())
{
}

CAGD::CmdStatus CAGD::CmdPoint::Perform()
{
    // 什么都不用做
    return CmdStatus::PERFORM;
}

CAGD::CmdStatus CAGD::CmdPoint::Step(char c)
{
    if (c == 'l')
    {
        // 捕获点击点
        auto P = m_context.GetInfo().points[0];
        auto Q = m_context.GetSpacePoint(P);
        auto HQ = Handle(GeomPoint)(new GeomPoint(Q));
        auto obj = Handle(AIS_Point)(new AIS_Point(HQ));
        m_context.CreateObject(obj);

        return CmdStatus::STEP;
    }

    return CmdStatus::KEEP;
}

CAGD::CmdStatus CAGD::CmdPoint::Move()
{
    // 什么都不做
    return CmdStatus::KEEP;
}

CAGD::CmdStatus CAGD::CmdVector::Step(char c)
{
    // 全局记录点
    static Handle(BPnt) point = nullptr;

    if (c == 'l')
    {
        // 获得选中点
        if (point == nullptr)
        {
            // 记录当前位置
            auto obj = m_context.GetSelected();
            if (obj == nullptr || obj->GetType() != AIS_Type::POINT)
            {
                auto P = m_context.GetInfo().points[0];
                auto Q = m_context.GetSpacePoint(P);
                point = Handle(BPnt)(new BPnt(Q));
            }
            else
                point = Handle(BPnt)(new BPnt(std::dynamic_pointer_cast<AIS_Point>(obj)->GetPoint()->Point()));
        }
        else
        {
            BPnt P1;
            auto obj = m_context.GetSelected();

            // 如果选中一个点，则连接这两个点
            if (obj != nullptr && obj->GetType() == AIS_Type::POINT)
                P1 = std::dynamic_pointer_cast<AIS_Point>(obj)->GetPoint()->Point();
            else
                P1 = m_context.GetSpacePoint(m_context.GetInfo().points[1]);

            // 计算点的距离，如果太近就丢弃
            auto P0 = *point;
            if (P1 == P0)
                return CmdStatus::KEEP;

            // 获得起点，得到向量
            auto Q0 = Handle(GeomPoint)(new GeomPoint(P0));
            auto V = Handle(GeomVector)(new GeomVector(P1 - P0));

            auto vec = Handle(AIS_Vector)(new AIS_Vector(V, Q0));
            m_context.CreateObject(vec);

            // 移除记录
            point = nullptr;
        }

        return CmdStatus::STEP;
    }

    return CmdStatus::KEEP;
}

CAGD::CmdStatus CAGD::CmdCurvePainter::Step(char c)
{
    if (c == 'l')
    {
        // 捕获点击点
        auto P = m_context.GetInfo().points[0];
        auto Q = m_context.GetSpacePoint(P);

        // 构造点云
        auto G = Handle(GeomPoint)(new GeomPoint(Q));
        auto ap = Handle(AIS_Point)(new AIS_Point(G));
        ap->SetActive(false);
        m_context.CreateObject(ap);
        m_points.push_back(ap);

        return CmdStatus::STEP;
    }

    return CmdStatus::KEEP;
}

CAGD::CmdStatus CAGD::CmdCurvePainter::Perform()
{
    // 标记删除点云，注意一定要通过消息传播，只是标记点云不足以删除所有子节点
    for (auto ap : m_points)
        ap->RecvMessage(Message::DEAD);

    return CmdStatus::PERFORM;
}

CAGD::CmdStatus CAGD::CmdCurveBuilder::Perform()
{
    // 构造物体
    if (m_curve != nullptr)
    {
        Handle(AIS_Curve) c(new AIS_Curve(m_curve));
        m_context.CreateObject(c);
    }

    return CmdCurvePainter::Perform();
}

CAGD::CmdStatus CAGD::CmdSurfaceBuilder::Perform()
{
    // 构造物体
    if (m_surface != nullptr)
    {
        Handle(AIS_Surface) c(new AIS_Surface(m_surface));
        m_context.CreateObject(c);
    }

    return CmdSurfacePainter::Perform();
}

CAGD::CmdStatus CAGD::CmdSelector::Step(char c)
{
    if (c == 'l')
    {
        auto obj = m_context.GetSelected();
        Handle(TopoBase) topo = nullptr;
        if (obj != nullptr)
        {
            switch (obj->GetType())
            {
            case AIS_Type::POINT: {
                topo = std::dynamic_pointer_cast<AIS_Point>(obj)->GetVertex();
                break;
            }
            case AIS_Type::CURVE: {
                topo = std::dynamic_pointer_cast<AIS_Curve>(obj)->GetEdge();
                break;
            }
            case AIS_Type::SURFACE: {
                topo = std::dynamic_pointer_cast<AIS_Surface>(obj)->GetFace();
                break;
            }
            case AIS_Type::MESH: {
                topo = std::dynamic_pointer_cast<AIS_Mesh>(obj)->GetTopoMesh();
                break;
            }
            }
        }

        if (topo != nullptr)
        {
            m_objs.push_back(topo);
            return CmdStatus::STEP;
        }
    }

    return CmdStatus::KEEP;
}

CAGD::CmdStatus CAGD::CmdSelector::Move()
{
    // 什么都不做
    return CmdStatus::KEEP;
}

CAGD::CmdStatus CAGD::CmdSelector::Perform()
{
    // 什么都不用做
    return CmdStatus::PERFORM;
}
